#include "uart.h"
#include "commonDefine.h"
 
int HiSerfd; 
void HI_Serial_Close(int fd);
  
void Hi_sigsegv(int dumy __attribute__((unused)))
{
	if(HiSerfd > 0)
		HI_Serial_Close(HiSerfd);
	ERRO_PRT("Hi Serial Caught SIGSEGV, Abort!\n");
	fclose(stderr);
	abort();
}
 
void Hi_sigterm(int dumy __attribute__((unused)))
{
	if(HiSerfd > 0)
		HI_Serial_Close(HiSerfd);
	ERRO_PRT("Hi Serial Caught SIGTERM, Abort!\n");
	fclose(stderr);
	exit(0);
}
 
void Hi_init_signals(void)
{
	struct sigaction sa;
	sa.sa_flags = 0;
	
	sigemptyset(&sa.sa_mask);
	sigaddset(&sa.sa_mask, SIGSEGV);
	sigaddset(&sa.sa_mask, SIGTERM);
	sigaddset(&sa.sa_mask, SIGPIPE);
	
	sa.sa_handler = Hi_sigsegv;
	sigaction(SIGSEGV, &sa, NULL);
 
	sa.sa_handler = Hi_sigterm;
	sigaction(SIGTERM, &sa, NULL);
 
	sa.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &sa, NULL);
}
 
void HI_Serial_Usage(void)
{
    printf("Usage:\n");
    printf("\tmyhicom [-d] <HiSerialDevice> [-s] get netdeviece info [-rw] read or wite select\n");
    printf("\tmyhicom [-h] for more usage\n");
    printf("\tmyhicom [-v] the verson of the sofware\n");
	printf("\tExample:\n\tmyhicom -d /dev/ttyAMA0 -s 115200 -w HiSerial:HelloWorld\n");
}
 
int HI_Serial_Open(const char* HiSerDevice)  
{  
    int fd;
		
	 fd = open( HiSerDevice, O_RDWR|O_NOCTTY);//  O_RDWR ： 可读可写 
											  //  O_NOCTTY ：该参数不会使打开的文件成为该进程的控制终端。如果没有指定这个标志，那么任何一个 输入都将会影响用户的进程。
 											  //  O_NDELAY ：这个程序不关心DCD信号线所处的状态,端口的另一端是否激活或者停止。如果用户不指定了这个标志，则进程将会一直处在睡眠状态，直到DCD信号线被激活。

	// fd = open(HiSerDevice, O_RDWR|O_NOCTTY|O_NDELAY);  
	if (-1 == fd)  
	{  
		perror("HiSerial Can't Open Serial HiSerDevice");  
		return(-1);  
	}  
	//恢复串口为阻塞状态                                 
	if(fcntl(fd, F_SETFL, 0) < 0)  
	{  
		INFO_PRT("fcntl failed!\n");  
		return(-1);  
	}       
	else  
	{  
		INFO_PRT("fcntl=%d\n",fcntl(fd, F_SETFL,0));  
	}  
	//测试是否为终端设备,需要注释掉，否则只能在终端运行程序。      
	// if(0 == isatty(STDIN_FILENO))  
	// {  
	// 	INFO_PRT("standard input is not a terminal device\n");  
	// 	return(-1);  
	// }  
	// else  
	// {  
	// 	INFO_PRT("isatty success!\n");  
	// }                
	INFO_PRT("fd->open=%d\n",fd);  
	return fd;  
}  
 
void HI_Serial_Close(int fd)  
{  
	if(fd > 0)
		close(fd); 
	return;	
}  
 
int HI_Serial_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)  
{  
     
	
	// int   status;  
	int   speed_arr[] = {B921600,B460800,B230400,B115200, B19200, B9600};  
	int   name_arr[] = {921600,460800,230400,115200,19200,9600};  
           
	struct termios options;  
     
 
	if( tcgetattr( fd,&options)  !=  0)  
	{  
		perror("SetupSerial 1");      
		return(-1);   
	}  
    
    //set buater rate 
	for (size_t i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)  
	{  
		if  (speed == name_arr[i])  
		{               
			cfsetispeed(&options, speed_arr[i]);   
			cfsetospeed(&options, speed_arr[i]);    
		}  
	}       
     
    //set control model 
    options.c_cflag |= CLOCAL;  //清bit位 关闭流控字符 0x11 0x13
    options.c_cflag |= CREAD;  //清bit位 关闭流控字符 0x11 0x13
    options.c_iflag &= ~(INLCR|ICRNL);//清bit位 关闭字符映射 0x0a 0x0d
    options.c_iflag &= ~(IXON);//清bit位 关闭流控字符 0x11 0x13
    
    //set flow control
    switch(flow_ctrl)  
    {  
        
		case 0 ://none  
              options.c_cflag &= ~CRTSCTS;  
              break;     
        
		case 1 ://use hard ware 
              options.c_cflag |= CRTSCTS;  
              break;  
		case 2 ://use sofware
              options.c_cflag |= IXON | IXOFF | IXANY;  
              break;  
    }  
  
    //select data bit   
    options.c_cflag &= ~CSIZE;  
    switch (databits)  
    {    
		case 5    :  
                     options.c_cflag |= CS5;  
                     break;  
		case 6    :  
                     options.c_cflag |= CS6;  
                     break;  
		case 7    :      
                 options.c_cflag |= CS7;  
                 break;  
		case 8:      
                 options.c_cflag |= CS8;  
                 break;    
		default:     
                 fprintf(stderr,"Unsupported data size\n");  
                 return (-1);   
    }  
    //select parity bit 
    switch (parity)  
    {    
		case 'n':  
		case 'N'://无奇偶校验位  
                 options.c_cflag &= ~PARENB;   
                 options.c_iflag &= ~INPCK;      
                 break;   
		case 'o':    
		case 'O'://设置为奇校验    
                 options.c_cflag |= (PARODD | PARENB);   
                 options.c_iflag |= INPCK;               
                 break;   
		case 'e':   
		case 'E'://设置为偶校验  
                 options.c_cflag |= PARENB;         
                 options.c_cflag &= ~PARODD;         
                 options.c_iflag |= INPCK;        
                 break;  
		case 's':  
		case 'S'://设置为空格    
                 options.c_cflag &= ~PARENB;  
                 options.c_cflag &= ~CSTOPB;  
                 break;   
        default:    
                 fprintf(stderr,"Unsupported parity\n");      
                 return (-1);   
    }   
    // set stopbit  
    switch (stopbits)  
    {    
		case 1:     
                 options.c_cflag &= ~CSTOPB; break;   
		case 2:     
                 options.c_cflag |= CSTOPB; break;  
		default:     
                       fprintf(stderr,"Unsupported stop bits\n");   
                       return (-1);  
    }  
     
	//修改输出模式，原始数据输出    
	options.c_oflag &= ~OPOST;  
    
	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  
	//options.c_lflag &= ~(ISIG | ICANON);  
     
    //set wait time   主要影响read函数
	/* options.c_cc[VTIME] = X; 　　//设置从获取到1个字节后开始计时的超时时间

		options.c_cc[VMIN] = Y;　　 //设置要求等待的最小字节数

		在原始模式下对read()函数的影响：

		1、X=0，Y!=0。函数read()只有在读取了Y个字节的数据或者收到一个信号的时候才返回；

		2、X!=0，Y=0。即使没有数据可以读取，read()函数等待X时间量后返回；

		3、X!=0,Y!=0。第一个字节数据到时开始，最先满足收到Y个字节或达超时时间X任意一个条件，read()返回；

		4、X=0,Y=0。即使读取不到任何数据，函数read也会立即返回。 */
    options.c_cc[VTIME] = 1;    /* 读取一个字符等待1*(1/10)s */      
    options.c_cc[VMIN] = 8;    /* 读取字符的最少个数为xx，单位是字节 */  
     
  
    tcflush(fd,TCIFLUSH);  
     
    // //激活配置 (将修改后的termios数据设置到串口中）  
    if (tcsetattr(fd,TCSANOW,&options) != 0)    
	{  
		perror("com set error!\n");    
		return -1;   
	}  
    return 0;   
}  
 

int HI_Serial_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)  
{  
    // int err;  
    //设置串口数据帧格式  
    if (HI_Serial_Set(fd,speed,flow_ctrl,databits,stopbits,parity) == -1)  
	{                                                           
		return -1;  
	}  
    else  
	{  
		return  0;  
	}  
}  
 
int HI_Serial_Send(int fd,const char *send_buf,int data_len)  
{  
    int len = 0;  
     
    len = write(fd,send_buf,data_len);  
    if (len == data_len )  
	{  
		//INFO_PRT("send length %d,data is %s\n",len,send_buf);
		return len;  
	}       
    else     
	{                   
		tcflush(fd,TCOFLUSH);  
		return -1;  
	}  
     
} 
 
int HI_Serial_Recv(int fd, char *rcv_buf,int data_len)  
{  
	int len,fs_sel;  
    fd_set fs_read;  
     
    struct timeval time;  
     
    FD_ZERO(&fs_read);  
    FD_SET(fd,&fs_read);  
     
    time.tv_sec = 2;  
    time.tv_usec = 0;  
    // len = read(fd,rcv_buf,data_len);  
    // select fdset
    fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);  
    if(fs_sel)  
	{  
		len = read(fd,rcv_buf,data_len);  
		INFO_PRT("HiSeral Receive Data = %s len = %d fs_sel = %d\n",rcv_buf,len,fs_sel);   
	}  
    else  
	{  
		ERRO_PRT("Hiserial haven't data receive!");  
		return -1;  
	}

	return len;      
}

/* 
void *uart_recv_task(void *arg)
{
	int len;
	char HiSerialDev[32]="/dev/ttyAMA0";
	// char sendbuf[1024]={0};
	char recvbuf[1024]={0};
	int SerialSpeed = 115200;
    int HiSerfd;
    int i;
	
	// Hi_init_signals();
	// HI_Serial_Usage();		
	
    HiSerfd = HI_Serial_Open(HiSerialDev);
    HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N');
    while(1)
    {
    len = HI_Serial_Recv(HiSerfd, recvbuf,sizeof(recvbuf)); 
    // printf("serial_recv length is %d\n",len); 
    if(len > 0)  
    {  
        INFO_PRT(" ttyAMA0:recv origin data \n");
        // recvbuf[len] = '\0';  
        for (i = 0;i < len ;i++)
        {
            printf("%02x  ",recvbuf[i]);  
        }
        printf("\n");  
        // memset(recvbuf,0,sizeof(recvbuf));
        //break;  
    }  
    else  
    {  
    //     printf("Hiserial haven't data receive \n");  
    }  
    // sleep(2); 						 
    }
				
    // INFO_PRT("myHicom write %s\n",optarg);
    // HiSerfd = HI_Serial_Open(HiSerialDev);
    // printf("fd = %d device = %s speed = %d\n",HiSerfd,HiSerialDev,SerialSpeed);
    // HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N');					 
    // sprintf(sendbuf,"%s\n",optarg);					 
    // HI_Serial_Send(HiSerfd, sendbuf, strlen(sendbuf)+1); 
    // if(HiSerfd > 0)
    //     HI_Serial_Close(HiSerfd);					
    // break;
	
	return 0;
}

void *uart_send_task(void *arg)
{
	char HiSerialDev[32]="/dev/ttyAMA0";
	char sendbuf[1024]="HelloWorld1234567890";
	// char recvbuf[1024]={0};
	// char sendbuf[] = {0};
	int SerialSpeed = 115200;
    int HiSerfd;
	
	// Hi_init_signals();
	// HI_Serial_Usage();		
	
    HiSerfd = HI_Serial_Open(HiSerialDev);
    HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N');
    while(1)
    {
  		HI_Serial_Send(HiSerfd, sendbuf, strlen(sendbuf)+1); 
        sleep(1);			 
    }
				
    // INFO_PRT("myHicom write %s\n",optarg);
    // HiSerfd = HI_Serial_Open(HiSerialDev);
    // printf("fd = %d device = %s speed = %d\n",HiSerfd,HiSerialDev,SerialSpeed);
    // HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N');					 
    // sprintf(sendbuf,"%s\n",optarg);					 
    // HI_Serial_Send(HiSerfd, sendbuf, strlen(sendbuf)+1); 
    // if(HiSerfd > 0)
    //     HI_Serial_Close(HiSerfd);					
    // break;
	
	return 0;
}

*/
